package thread;

import java.util.ArrayList;

// RR queue
class MyBlockQueue{
    private final String[] buf;      // 固定数组做环形缓冲区
    private final int capacity;      // 容量
    private int size;                // 当前元素个数
    private int head;                // 读指针
    private int tail;                // 写指针
    private final Object locker = new Object();

    public MyBlockQueue(int capacity){
        this.buf = new String[capacity];
        this.capacity = capacity;
        this.size = 0;
        this.head = 0;
        this.tail = 0;
    }
    public void put(String elem) throws InterruptedException {
        synchronized (locker){
            while (size == capacity){          // 必须 while 防止虚假唤醒
                locker.wait();
            }
            buf[tail] = elem;                  // 覆盖写入，不插入
            tail = (tail + 1) % capacity;      // 环形前进
            size++;
            locker.notifyAll();                // 可能有多个等待者
        }
    }
    public String take() throws InterruptedException {
        synchronized (locker){
            while (size == 0){                 // 必须 while 防止虚假唤醒
                locker.wait();
            }
            String tmp = buf[head];
            buf[head] = null;                  // 帮助 GC
            head = (head + 1) % capacity;      // 环形前进
            size--;
            locker.notifyAll();
            return tmp;
        }
    }

    public int getSize() {
        synchronized (locker) {
            return size;
        }
    }
};


public class Demo9_MyBlockQueue {
    public static void main(String[] args) {
        MyBlockQueue blkque = new MyBlockQueue(10);
        Thread producer = new Thread(()->{
            int n = 0;
            while(true)
                try {
                    blkque.put(""+n);
                    System.out.println("produced: " + n);
                    ++n;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
        });
        Thread consumer = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            try {
                while(true){
                    String tmp = blkque.take();
                    System.out.println("consumed:" + tmp + ","+ "size = " + blkque.getSize()+ " " +Thread.currentThread().getName());
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        });
        producer.start();
        consumer.start();



    }
}
